package com.fenghuaxz.rpcframework;

import com.fenghuaxz.rpcframework.model.MsgCallback;
import com.fenghuaxz.rpcframework.model.SyncCallback;
import io.netty.bootstrap.AbstractBootstrap;
import io.netty.channel.group.ChannelGroup;
import io.netty.channel.group.DefaultChannelGroup;
import io.netty.handler.codec.ByteToMessageDecoder;
import io.netty.handler.codec.MessageToByteEncoder;
import io.netty.util.concurrent.GlobalEventExecutor;

import java.net.InetSocketAddress;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 创建 : 七羽软件工作室
 * 时间 : 2017/9/28 : 0:15
 */
public abstract class BaseContext extends BroadcastContext{

    protected static Class<MessageToByteEncoder> encoder = null;
    protected static Class<ByteToMessageDecoder> decoder = null;

    static{
        //如果当前消息解码/编码器为null 则加载默认编码/解码器
        try {
            String defaultEncoder = "com.fenghuaxz.rpcframework.codec.MsgEncoder";
            String defaultDecoder = "com.fenghuaxz.rpcframework.codec.MsgDecoder";
            encoder = encoder != null ? encoder : (Class<MessageToByteEncoder>) Class.forName(defaultEncoder);
            decoder = decoder != null ? decoder : (Class<ByteToMessageDecoder>) Class.forName(defaultDecoder);
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    /**
     * 设置消息编码器
     * @param encoder
     */
    public static final <T extends MessageToByteEncoder> void setEncoder(Class<T> encoder){
        BaseContext.encoder = (Class<MessageToByteEncoder>) encoder;
    }

    /**
     * 设置消息解码器
     * @param decoder
     */
    public static final <T extends ByteToMessageDecoder> void setDecoder(Class<T> decoder){
        BaseContext.decoder = (Class<ByteToMessageDecoder>) decoder;
    }

    /**
     * 设置阻塞式消息请求超时(毫秒)
     * @param millis
     */
    public static final void setTimeout(long millis){
        SyncCallback.SYNC_RPCREQUEST_TIMEOUT_MILLIS = millis;
    }

    protected OnBindCheckListener bindCheckListener;
    protected OnLimitChannelListener limitChannelListener;
    protected OnClosedListener closedListener;
    protected final ReentrantLock safe = new ReentrantLock();

    /**
     * 设置channel绑定监听
     * @param listener
     */
    public final void setOnBindCheckListener(OnBindCheckListener listener){
        this.bindCheckListener = listener;
    }

    /**
     * 设置channel信任监听
     * @param listener
     */
    public final void setOnLimitChannelListener(OnLimitChannelListener listener){
        this.limitChannelListener = listener;
    }

    /**
     * 设置channel断开监听
     * @param listener
     */
    public final void setOnClosedListener(OnClosedListener listener){
        this.closedListener = listener;
    }

    protected final ConcurrentMap<String,SafeRemoteObject> handlerObjects = new ConcurrentHashMap<>();

    /**
     * 添加处理程序对象
     * @param name
     * @param object
     * @param <T>
     */
    public final <T extends SafeRemoteObject> void addHandler(String name,T object){
        this.handlerObjects.put(name, object);
    }

    /**
     * 获取处理程序对象
     * @param name
     * @return 如果不存在则返回 null
     */
    public final SafeRemoteObject getHandler(String name){
        return this.handlerObjects.get(name);
    }

    protected final  <T extends AbstractBootstrap> BaseContext open(T bootstrap,InetSocketAddress address) throws Exception{
        ReentrantLock lock = new ReentrantLock();
        Condition signal = lock.newCondition();
        BindRunnble runnble = new BindRunnble(bootstrap,address,lock,signal);

        lock.lock();
        try {
            new Thread(runnble).start();
            signal.await();
            Exception exp = runnble.exp;
            if (exp != null) throw exp;
            return this;
        }finally {
            lock.unlock();
        }
    }

    public abstract BaseContext bind(InetSocketAddress address) throws Exception;

    public abstract void close();
}
